package qj.ac.unifs;

import java.io.*;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.ZipInputStream;

import qj.util.*;
import qj.util.QFileUtil.QFile;
import qj.util.QFileUtil.QFileContent;
import qj.util.col.Tree;
import qj.util.funct.F1;
import qj.util.funct.Fs;
import qj.util.funct.P2;

public class UnifyReader {
	private final List<FileSet> fileSets;
	private final HashMap<String, byte[]> store;


	public static void main(String[] args) {
		UnifyWriter unifyWriter = new UnifyWriter();
		for (File dir : new File("../../commercial-apps/gunny-tool/gt-support/build/branch").listFiles()) {
			unifyWriter.writeDir(new File(dir, "client/data"), "branch:" + dir.getName());
		}
		unifyWriter.getReader();
	}

	public UnifyReader(List<FileSet> fileSets, HashMap<String, byte[]> store) {
		this.fileSets = fileSets;
		this.store = store;
	}

	public UnifyReader() {
		this(new LinkedList<FileSet>(), new HashMap<String, byte[]>());
	}

	public static UnifyReader read(File zipFile) {
		FileInputStream in = FileUtil.fileInputStream(zipFile);
		return read(in);
	}

	public static UnifyReader read(InputStream in) {
		final HashMap<String, byte[]> store = new HashMap<String, byte[]>();
		final List<FileSet> fileSets = new LinkedList<FileSet>();
		ZipUtil.eachEntry(new ZipInputStream(in), new P2<String,InputStream>() {public void e(String path, InputStream in) {
			if (path.startsWith("store/")) {
				store.put(path.substring("store/".length()), IOUtil.readDataNice(in));
			} else { // fileSets.txt
				readFileSets(in, fileSets);
			}
		}});
		
		return new UnifyReader(fileSets, store);
	}

	static void readFileSets(
			InputStream in,
			List<FileSet> fileSets) {
		BufferedReader br = new BufferedReader(new InputStreamReader(in));
		try {
			FileSet fileSet = null;
			for (String line;(line=br.readLine())!=null;) {
				if (fileSet==null && line.length()>0) {
					fileSet = new FileSet();
					fileSet.name = line;
					fileSet.files = new LinkedList<FileMd5>();
					fileSets.add(fileSet);
				} else if (line.length() > 0) {
					String[] split = line.split(":");
					fileSet.files.add(new FileMd5(split[1], split[0]));
				} else {
					fileSet = null;
				}
			}
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	public QFile toQFile(String... fileSets) {
		QFile dir = new QFile((String)null);
		for (String fileSetName : fileSets) {
			FileSet fileSet = getFileSet(fileSetName);
			if (fileSet==null) {
//				throw new RuntimeException("Not found fileSet: " + fileSetName);
				continue; // Skip
			}
			
			for (FileMd5 file : fileSet.files) {
				Tree<QFileContent> qNode = Tree.getTree(Tree.parsePaths(file.filePath), dir, Tree.MODE_FORCE, QFile.CONSTRUCTOR);
				if (qNode.value != null) {
					// Skip
				} else {
					byte[] content = store.get(file.md5);
					qNode.value = QFile.toValue(content);
				}
			}
		}
		return dir;
	}

	private FileSet getFileSet(String fileSetName) {
		for (FileSet fileSet : fileSets) {
			if (fileSet.name.equals(fileSetName)) {
				return fileSet;
			}
		}
		return null;
	}
}